home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / freeWAIS-sf-1.1 / ir / sockets.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-13  |  10.4 KB  |  419 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE    
  2.    No guarantees or restrictions.  See the readme file for the full standard 
  3.    disclaimer.  
  4.    5.29.90    Harry Morris, morris@think.com
  5. */
  6.  
  7. /* Copyright (c) CNIDR (see ../COPYRIGHT) */
  8.  
  9.  
  10. #ifndef lint
  11. static char *RCSid = "$Header: /usr/local/ls6/src+data/src/freeWAIS-sf/ir/RCS/sockets.c,v 1.7 1994/12/13 18:52:45 pfeifer Exp $";
  12. #endif
  13.  
  14. /* Change log:
  15.  * $Log: sockets.c,v $
  16.  * Revision 1.7  1994/12/13  18:52:45  pfeifer
  17.  * chip@chinacat.unicom.com (Chip Rosenthal) patches.
  18.  * Excluding the merge of libinv and libwais
  19.  *
  20.  * Revision 1.6  1994/11/29  10:44:03  pfeifer
  21.  * "matthew (m.) holiday" <holiday@bnr.ca>:
  22.  * I've been having some problems with server security, where the
  23.  * server was refusing connections from an authorized host.  Lo and behold,
  24.  * when the server accepted a connection from a client, the host_name and
  25.  * host_address variables were left as empty strings (and so never matched the
  26.  * entries in the DATA_SEC file)!  These need to be reset for each new client
  27.  * connection, which is what the following patch does.
  28.  *
  29.  * Revision 1.5  1994/07/13  07:53:26  pfeifer
  30.  * beta 02
  31.  *
  32.  * Revision 1.4  1994/05/20  12:57:23  pfeifer
  33.  * beta
  34.  *
  35.  * Revision 1.3  1994/03/08  21:06:51  pfeifer
  36.  * Patchlevel 04
  37.  *
  38.  * Revision 1.2  93/07/01  19:14:22  warnock
  39.  * Fix for gethostname from francois and jonathan
  40.  * 
  41.  * Revision 1.1  1993/02/16  15:05:35  freewais
  42.  * Initial revision
  43.  *
  44.  * Revision 1.23  92/05/06  17:34:41  jonathan
  45.  * Added Mach to some compiler switches.
  46.  * 
  47.  * Revision 1.22  92/04/28  15:21:14  jonathan
  48.  * Added decoding of IP address to DNS name in accept_client handler.
  49.  * 
  50.  * Revision 1.21  92/04/01  09:49:49  morris
  51.  * declared clr_socket static to stop gcc from complaining
  52.  * 
  53.  * Revision 1.20  92/03/24  10:35:32  jonathan
  54.  * Put a loop around connect in fd_connect_to_server to check if the connect
  55.  * was interrupted by a system call (usually a timer).  Retries if errno is
  56.  * EINTR.
  57.  * 
  58.  * Revision 1.19  92/02/16  12:38:22  jonathan
  59.  * Changed bzero's to memset's.
  60.  * 
  61.  * Revision 1.18  92/02/16  12:34:11  jonathan
  62.  * Removed code refering to NOINETNTOA, since we should use inet_ntoa.
  63.  * 
  64.  * Revision 1.17  92/02/12  13:48:21  jonathan
  65.  * Added "$Log" so RCS will put the log message in the header
  66.  * 
  67.  * 
  68. */
  69.  
  70. /*
  71.    Added code in fd_accept_client_connection to print source Inet address to
  72.    stderr. 
  73.    - Jonny G Fri Apr 12 1991
  74.  
  75. */
  76.  
  77. #define sockets_c
  78.  
  79. #include "sockets.h"
  80.  
  81. #ifdef NOTCPIP /* we don't have TCPIP */
  82.  
  83. void open_server (port,socket,size) long port; long* socket; long size; {}
  84. void accept_client_connection (socket,file) long socket; FILE** file; {}
  85. void close_client_connection (file) FILE* file; {}
  86. void close_server (socket) long socket; {}
  87. FILE *connect_to_server (host_name,port) char* host_name; long port; 
  88.                                   {return(NULL);}
  89. void close_connection_to_server (file) FILE* file; {}
  90.  
  91. #else /* there is TCPIP */
  92.  
  93. #include <errno.h>
  94. #include "cdialect.h"
  95. /* #include <string.h> */
  96. #include "panic.h"
  97.  
  98. #if (defined(ultrix) || defined(BSD) || defined(Mach))
  99. extern int errno;
  100. #endif /* ultrix BSD or Mach */
  101.  
  102. extern char *sys_errlist[];
  103.  
  104. char host_name[255], host_address[255];
  105.  
  106. /* XXX
  107. still need:
  108.  non-blocking modes
  109.  special send/recieve functions? (there are now some in ui.c)
  110.  asynchronous calls?
  111. */
  112.  
  113. /* define the number of queued connections allowable on each port */
  114. #define QUEUE_SIZE 3
  115.  
  116. /*---------------------------------------------------------------------------*/
  117. /* Server functions                                                          */
  118. /*---------------------------------------------------------------------------*/
  119.  
  120. static boolean clr_socket _AP((struct sockaddr_in *address, long portnumber,
  121.             long* sock));
  122.  
  123. static boolean clr_socket(address, portnumber, sock)
  124.      struct sockaddr_in *address;
  125.      long portnumber;
  126.      long *sock;
  127. {
  128.   if (errno == EADDRINUSE) {
  129.     /* Try connecting to it */
  130.     if (connect(*sock, address, sizeof (struct sockaddr_in)) == 0) {
  131.       close(*sock);
  132.       waislog(WLOG_HIGH, WLOG_ERROR,
  133.           "Cannot bind port %ld: (Address already in use).",
  134.           portnumber);
  135.       waislog(WLOG_HIGH, WLOG_ERROR, "waisserver is already running on this system");
  136.       panic("Exiting");
  137.     } else {
  138.       /* Connection failed; probably socket in FIN_WAIT */
  139.       int one = 1;
  140.  
  141.       (void) close(*sock);
  142.       if ((*sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  143.     panic("Open socket failed in trying to clear the port.");
  144.       /*printf("Error binding port %d: (address already in use).\n\
  145. Attempting to clear stale socket...", portnumber);*/
  146.       if ( setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, 
  147.               &one, sizeof (one)) < 0) {
  148.     /*printf("Warning: Setsockopt SO_REUSEADDR failed.");*/
  149.       }
  150.       address->sin_family = AF_INET;
  151.       address->sin_addr.s_addr = INADDR_ANY;
  152.  
  153.       address->sin_port = (unsigned short int)htons(portnumber);
  154.  
  155.       if (bind(*sock, address, sizeof(*address)) == 0) {
  156.     /*printf("Successfully cleared stale EADDRINUSE error");*/
  157.       }
  158.     }
  159.   }
  160.   return(true);
  161. }
  162.  
  163.  
  164. void
  165. open_server(port,fd,size)
  166. long port;
  167. long* fd;
  168. long size;
  169. { struct sockaddr_in address;
  170.  
  171.   memset(&address, 0, sizeof(address));
  172.  
  173.   /* open the fd */
  174.   if ((*fd = socket(AF_INET,SOCK_STREAM,0)) < 0){
  175.     panic("can't get file descriptor for socket: %s", sys_errlist[errno]);
  176.   }
  177.  
  178.   address.sin_family = AF_INET;
  179.   address.sin_addr.s_addr = htonl(INADDR_ANY);
  180.   address.sin_port = (unsigned short int)htons(port);
  181.   if (bind(*fd,(struct sockaddr*)&address,sizeof(struct sockaddr)) < 0)
  182.     clr_socket(&address, port, fd);
  183.  
  184.   if (listen(*fd,QUEUE_SIZE) < 0)
  185.     panic("can't open server: %s", sys_errlist[errno]);
  186. }
  187.  
  188.  
  189.  
  190. /* This is a lower level function provided for use by the lisp version of
  191.  * this library 
  192.  * XXX should support non-blocking mode
  193.  */
  194.  
  195. #include <arpa/inet.h>
  196.  
  197. void
  198. fd_accept_client_connection(socket,fd)
  199. long socket;
  200. long* fd;
  201. { /* accept an input connection, and open a file on it */
  202.   struct sockaddr_in source;
  203.   int sourcelen;
  204. #ifdef BSD
  205.   struct in_addr {
  206.     union {
  207.       struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
  208.       u_long S_addr;
  209.     } S_un;
  210.   } addr_p;
  211. #endif /* BSD */
  212.  
  213.   sourcelen = sizeof(struct sockaddr_in);
  214.  
  215.   do {
  216.     errno = 0;
  217.     *fd = accept(socket, &source, &sourcelen);
  218.   } while (*fd < 0 && errno == EINTR);
  219.  
  220.   if(source.sin_family == AF_INET) {
  221.     struct hostent *peer = NULL;
  222.     host_name[0] = '\0';
  223.  
  224. #ifdef __DGUX__
  225.     peer = gethostbyaddr((char *)&source.sin_addr.s_addr, 4, AF_INET);
  226. #else
  227.     peer = gethostbyaddr(&source.sin_addr, 4, AF_INET);
  228. #endif
  229.  
  230.       sprintf(host_address, "%s",
  231. #if defined(sparc) && defined(__GNUC__) && defined(INET_NTOA_WITH_POINTER)
  232.         inet_ntoa(&source.sin_addr)
  233. #else
  234.         inet_ntoa(source.sin_addr)
  235. #endif              /* sparc */
  236.         );
  237.  
  238.     if(peer != NULL) {
  239.       sprintf(host_name, "%s", peer->h_name);
  240.  
  241.       waislog(WLOG_MEDIUM, WLOG_CONNECT,
  242.           "Accepted connection from: %s [%s]",
  243.          host_name[0] ? host_name : "?", host_address);
  244.     }
  245.     else {
  246.       waislog(WLOG_MEDIUM, WLOG_CONNECT,
  247.           "Accepted connection from: [%s]", host_address);
  248.     }
  249.   }
  250.   if (*fd < 0)
  251.     panic("can't accept connection");
  252. }
  253.  
  254.  
  255. /* This is the prefered C function for accepting client requests */
  256. void
  257. accept_client_connection(socket,file)
  258. long socket;
  259. FILE** file;
  260. { long fd; /* file descriptor actually used */
  261.   fd_accept_client_connection(socket,&fd);
  262.   if ((*file = fdopen(fd,"r+")) == NULL)
  263.     panic("can't accept connection");
  264. }
  265.  
  266. /* When a server wants to end the session with a client */
  267. void
  268. close_client_connection(file)
  269. FILE* file;
  270.   fclose(file);
  271. }
  272.  
  273. /* when exiting the top level server process (not the forked
  274.    server processes that come one per client).
  275.    Maybe we need to do this once per client as well.
  276. */
  277. void
  278. close_server(socket)
  279. long socket;
  280. {
  281.   close(socket);
  282. }
  283.  
  284. /*---------------------------------------------------------------------------*/
  285. /* Client functions                                                          */
  286. /*---------------------------------------------------------------------------*/
  287.  
  288. /* This is a lower level function provided for use by the lisp version of
  289.  * this library 
  290.  * XXX should support non-blocking mode
  291.  */
  292.  
  293. #define HOSTNAME_BUFFER_SIZE 120
  294. #define MAX_RETRYS 10
  295.  
  296. boolean
  297. fd_connect_to_server(hname,port,fd)
  298. char* hname;
  299. long port;
  300. long* fd;
  301. {
  302.   char hostnamebuf[80];
  303.   long rc, i;
  304.   struct hostent *host;
  305.   /* struct servent *service = NULL; not used */
  306.   struct sockaddr_in name;
  307.  
  308.   memset((char *)&name, 0,sizeof (name));
  309.  
  310. #ifdef __DGUX__
  311.   name.sin_addr = inet_addr(hname);
  312. #else
  313.   name.sin_addr.s_addr = inet_addr(hname);
  314. #endif
  315.  
  316.   if (name.sin_addr.s_addr != -1) {
  317.     name.sin_family = AF_INET;
  318.     (void) strcpy(hostnamebuf, hname);
  319.   }
  320.   else {
  321.     host = gethostbyname(hname);
  322.  
  323.     if(NULL == host){
  324.       return FALSE;
  325.     }
  326.  
  327.     name.sin_family = host->h_addrtype;
  328. #ifdef h_addr
  329.     bcopy(host->h_addr_list[0],
  330.       (caddr_t)&name.sin_addr, host->h_length);
  331. #endif
  332.     (void) strcpy(hostnamebuf, host->h_name);
  333.   }
  334.   hname = hostnamebuf;
  335.  
  336.   name.sin_port = (unsigned short int)htons(port);
  337.  
  338.   *fd = socket (AF_INET, SOCK_STREAM, 0);
  339.   for(i = 0; i < MAX_RETRYS; i++) {
  340.     rc = connect (*fd, &name, sizeof (name));
  341.     if(rc == 0) return TRUE;
  342.     else if(errno == EINTR){
  343.       sleep(1);
  344.     }
  345.     else {
  346.       perror("Connect to socket did not work (1)");
  347.       return FALSE;
  348.     }
  349.   }
  350.   return FALSE;
  351. }
  352.  
  353. /* This is the prefered C function for initiating client requests */
  354. FILE *
  355. connect_to_server(hname,port)
  356. char* hname;
  357. long port;
  358. {
  359.   FILE* file;
  360.   long fd;
  361.   if(fd_connect_to_server(hname,port,&fd) == FALSE) {
  362.     perror("Connect to socket did not work (2)");
  363.     return NULL;
  364.   }
  365.  
  366.   if ((file = fdopen(fd,"r+")) == NULL) {
  367.     perror("Connect to socket did not work (3)");
  368.     return NULL;
  369.   }
  370.  
  371.   return file;
  372. }
  373.  
  374. void
  375. close_connection_to_server(file)
  376. FILE* file;
  377. {
  378.   fclose(file);
  379. }
  380.  
  381. /*---------------------------------------------------------------------------*/
  382.  
  383. #endif /* there is TCPIP */
  384.  
  385. /* Francois and Jonathan Goldman - hostname fix */
  386. char *
  387. mygethostname(hostname, len)
  388. char *hostname;
  389. long len;
  390. {
  391.     char    name[255];
  392.     struct    hostent    *h;
  393.  
  394.     gethostname(name, 254);
  395.     strcpy(hostname,name);
  396.  
  397.     h = gethostbyname(name);
  398.  
  399.     if ( (h = gethostbyname(name)) != NULL) {
  400.         if ( (strlen(h->h_name) >= len) && ( len > 0 ) ) {
  401.             strncpy(hostname, h->h_name,len-1);
  402.         }
  403.         else {
  404.             strcpy(hostname, h->h_name);
  405.         }
  406.     }
  407.     else {
  408.         if ( ( strlen(name) >= len) && (len > 0 ) ) {
  409.             strncpy(hostname, name, len-1);
  410.         }
  411.         else {
  412.             strcpy(hostname, name);
  413.         }
  414.     }
  415.  
  416.     return(hostname);
  417. }
  418.